#ifndef NEURON_H_
#define NEURON_H_

#include "Activation.h"
#include "Learning.h"
#include "Defines.h"
#include "CSVFile.h"

/*
 * =====================================================================================
 *        Class:  Neuron
 *  Description:  Classe que representa um neurônio
 * =====================================================================================
 */
class Neuron
{

public:

    /*-----------------------------------------------------------------------------
     *  Constrói um neurônio passando o nº de variáveis de entrada, a função de
     *  ativação e o aprendizado
     *  Os pesos do neurônio serão calculados randomicamente se csv for nulo
     *-----------------------------------------------------------------------------*/
    Neuron(uint nInVars, ActivationPtr activation, LearningPtr learning,
            CSVFilePtr csv = CSVFilePtr());

    /*-----------------------------------------------------------------------------
     *  Retorna os pesos do neurônio
     *-----------------------------------------------------------------------------*/
    vdouble& getWeights() { return weights; }

    /*-----------------------------------------------------------------------------
     *  Retorna os pesos do neurônio
     *-----------------------------------------------------------------------------*/
    double getWeight(uint i) { return weights[i]; }

    /*-----------------------------------------------------------------------------
     *  Retorna o valor de internalOutput
     *-----------------------------------------------------------------------------*/
    double getNonActivatedOutput() { return nonActivatedOutput; }

    /*-----------------------------------------------------------------------------
     *  Retorna o valor de externalOutput
     *-----------------------------------------------------------------------------*/
    double getActivatedOutput() { return activatedOutput; }

    /*-----------------------------------------------------------------------------
     *  Reseta os pesos do neurônio
     *-----------------------------------------------------------------------------*/
    void reset();

    /*-----------------------------------------------------------------------------
     *  Retorna o output do neurônio dada uma entrada
     *-----------------------------------------------------------------------------*/
    double getOutput(vdoublePtr input);

    /*-----------------------------------------------------------------------------
     *  Retorna o erro do neurônio passando a saída esperada
     *-----------------------------------------------------------------------------*/
    double getError(double exepcted);

    /*-----------------------------------------------------------------------------
     *  Retorna o error do neurônio passando os erros da próxima camada e seus pesos
     *-----------------------------------------------------------------------------*/
    double getError(vdoublePtr nextErrors, vdoublePtr nextWeights);

    /*-----------------------------------------------------------------------------
     *  Atualiza seus pesos com base no erro obtido
     *-----------------------------------------------------------------------------*/
    void update(vdoublePtr input);

    /*-----------------------------------------------------------------------------
     *  Imprime os pesos
     *-----------------------------------------------------------------------------*/
    void print();

private:

    /*-----------------------------------------------------------------------------
     *  Retorna um valor aleatório baixo entre 0 e 0.1
     *-----------------------------------------------------------------------------*/
    double getRandom();

    /*-----------------------------------------------------------------------------
     *  Número de variáveis de entrada
     *-----------------------------------------------------------------------------*/
    uint nInVars;

    /*-----------------------------------------------------------------------------
     *  Função de ativação
     *-----------------------------------------------------------------------------*/
    ActivationPtr activation;

    /*-----------------------------------------------------------------------------
     *  Aprendizado
     *-----------------------------------------------------------------------------*/
    LearningPtr learning;

    /*-----------------------------------------------------------------------------
     *  Pesos
     *-----------------------------------------------------------------------------*/
    vdouble weights;

    /*-----------------------------------------------------------------------------
     *  Última saída externa ativada
     *-----------------------------------------------------------------------------*/
    double activatedOutput;

    /*-----------------------------------------------------------------------------
     *  Última saída interna não ativada
     *-----------------------------------------------------------------------------*/
    double nonActivatedOutput;

    /*-----------------------------------------------------------------------------
     *  Erro
     *-----------------------------------------------------------------------------*/
    double error;

};

/*-----------------------------------------------------------------------------
 *  Ponteiro
 *-----------------------------------------------------------------------------*/
typedef boost::shared_ptr<Neuron> NeuronPtr;

#endif /* NEURON_H_ */
